#pragma once

// #include "ui.hpp"
#include <string.h>

#include "./oled.hpp"
// #include "between_face_common.hpp"

namespace beef {

    enum class menu_type : uint8_t {
        no_value = 0,  // no value 类型的菜单项作用类似按钮，代表要立即执行的操作。
                       // 如果要用菜单项显示注释或纯文本，可将类型设为comment。

        unsigned_value,
        signed_value,
        hex_value,
        float_value,
        positive_float_value,

        option,
        comment,  // 注释行，与option 类似，可以用字符串数组显示帮助信息，
                  // 但值是可选的，如果len == 0，表示没有额外的帮助信息。
        check,

        // text,
    };


    // constexpr size_t MENU_ITEM_STR_LEN = 4;  // 菜单项字符串最大长度

    // static_assert(MENU_ITEM_STR_LEN >= 4);


    using ConstantStrArrayPtr = const char* const*;
    using ConstantStrArray = const char* const[];


    template <size_t N, typename T>
    constexpr size_t len_of_array(T (&arr)[N]) {
        return N;
    }


    union MenuItemData {
        uint32_t u;

        int32_t s;

        float f;  // 如果是浮点数类型，表示浮点数的值

        // char* text;  // 如果是字符串类型，指向字符串缓冲区，字符串以\0 结尾，
                     // 编辑字符串时，有可能不会从头开始，而是在中间随机的插入字符，
                     // 所以处理字符串时，需要ltrim，去掉左侧的空白和无效字符。
                     // 同样，index 里存储的字符串长度也可能是不可靠的。

        ConstantStrArrayPtr list;  // 如果是选项类型，表示选项列表
    };


    struct MenuItem {
        const char* label;  // 菜单项名称
        menu_type type;     // 菜单项类型

        int8_t id;  // 菜单项ID，用于标识菜单项，或存储与菜单项绑定的其他信息
        // bool clickable;  // 是否可点击

        uint8_t len;  // 如果是整数类型，表示整数的位数，主要用于指导编辑数据时需要多少个SpinBox；
                      // 如果是浮点，表示整数部分的位数，
                      // 如果是选项类型，表示选项的数量

        uint8_t index;  // 如果是选项类型，表示当前选中的选项索引
                        // 如果是check 类型，表示bool 值，0 false，1 true
                        // 如果是浮点类型，表示精度
                        // 如果是整数类型，表示乘10^index
                        // 如果是hex 类型，表示乘16^index

        // MenuItem 只关心菜单项的数据存储和显示，
        // 输入验证可以放在输入界面中处理，比如在输入超限后就不触发spin box 的dec 和inc，
        // 或者另外增加个验证器对象，和MenuItem 一对一绑定。
        // 另一方面，如果在MenuItem 里增加min 和max 成员作为验证，
        // 会增加结构复杂度，占用更多空间，很多时候只靠min 和max 又不足以验证。
        MenuItemData data;

       private:
        uint32_t dec_multiplier() const {
            switch (index) {
                case 0:
                    return 1;

                case 1:
                    return 10;

                case 2:
                    return 100;

                case 3:
                    return 1000;

                case 4:
                    return 10000;

                default:
                    uint32_t v = 1;
                    for (uint8_t i = index; i > 0; --i) {
                        v *= 10;
                    }
                    return v;
            }
        }


        uint32_t hex_multiplier() const {
            switch (index) {
                case 0:
                    return 1;

                case 1:
                    return 0x10;

                case 2:
                    return 0x100;

                case 3:
                    return 0x1000;

                case 4:
                    return 0x10000;

                default:
                    uint32_t v = 1;
                    for (uint8_t i = index; i > 0; --i) {
                        v <<= 4;
                    }
                    return v;
            }
        }


       public:
        MenuItem& item_label(const char* label) {
            this->label = label;
            return *this;
        }


        MenuItem& item_id(uint8_t i) {
            this->id = i;
            return *this;
        }


        bool checked() const {
            return type == menu_type::check && index != 0;
        }


        uint8_t number_len() const {
            switch (type) {
                case menu_type::unsigned_value:
                case menu_type::signed_value:
                case menu_type::hex_value:
                case menu_type::float_value:
                case menu_type::positive_float_value:
                    return len;

                default:
                    return 0;
            }
        }


        uint8_t multiplier() const {
            switch (type) {
                case menu_type::unsigned_value:
                case menu_type::signed_value:
                    return dec_multiplier();

                case menu_type::hex_value:
                    return hex_multiplier();

                default:
                    return 1;
            }
        }


        uint8_t float_precision() const {
            return (type == menu_type::float_value || type == menu_type::positive_float_value)
                     ? index
                     : 0;
        }


        uint8_t option_count() const {
            return (is_option() || is_comment()) ? len : 0;
        }


        uint8_t option_index() const {
            return type == menu_type::option ? index : 0;
        }


        const char* option_text() const {
            if (type == menu_type::option && index < len) {
                return data.list[index];
            }
            return nullptr;  // 如果索引越界，返回nullptr
        }


        void as_no_value() {
            type = menu_type::no_value;
            // len = 0;
            // index = 0;
        }


        void as_comment() {
            type = menu_type::comment;
            len = 0;  // 注释行没有长度
            // index = 0;  // 注释行没有索引
        }


        void as_help(ConstantStrArrayPtr text_list, uint8_t count) {
            type = menu_type::comment;
            data.list = text_list;
            len = count;
            index = 0;
        }


        template <uint8_t N>
        void as_help(const char* const (&text_list)[N]) {
            as_help(text_list, N);
        }


        void as_float(float value, uint8_t num_len = 3, uint8_t precision = 2) {
            type = menu_type::float_value;
            data.f = value;
            index = precision;
            len = num_len;
        }


        void as_unsigned_float(float value, uint8_t num_len = 3, uint8_t precision = 2) {
            type = menu_type::positive_float_value;
            data.f = value;
            index = precision;
            len = num_len;
        }


        void as_unsigned(uint32_t value, uint8_t num_len = 3, uint8_t index = 0) {
            type = menu_type::unsigned_value;
            data.u = value;
            len = num_len;
            this->index = index;
        }


        void as_signed(int32_t value, uint8_t num_len = 3, uint8_t index = 0) {
            type = menu_type::signed_value;
            data.s = value;
            len = num_len;
            this->index = index;
        }


        void as_hex(uint32_t value, uint8_t num_len = 3, uint8_t index = 0) {
            type = menu_type::hex_value;
            data.u = value;
            len = num_len;
            this->index = index;
        }


        void as_option(ConstantStrArrayPtr options, uint8_t count, uint8_t selected_index) {
            type = menu_type::option;
            data.list = options;
            len = count;
            index = selected_index < count ? selected_index : 0;  // 确保索引不越界
        }


        template <uint8_t N>
        void as_option(const char* const (&options)[N], uint8_t selected_index = 0) {
            as_option(&options[0], N, selected_index);
        }


        void set_option_index(uint8_t selected_index) {
            if (type == menu_type::option && selected_index < len) {
                index = selected_index;  // 确保索引不越界
            }
        }


        void as_check(bool checked) {
            type = menu_type::check;
            index = checked ? 1 : 0;  // 使用0或1表示false或true
        }


        void set_checked(bool checked) {
            if (type == menu_type::check) {
                index = checked ? 1 : 0;
            }
        }


        void toggle_check() {
            if (type == menu_type::check) {
                if (index == 1) {
                    index = 0;
                }
                else {
                    index = 1;
                }
            }
        }


        bool is_integer() const {
            return type == menu_type::unsigned_value || type == menu_type::signed_value || type == menu_type::hex_value;
        }


        bool is_unsigned() const {
            return type == menu_type::unsigned_value || type == menu_type::hex_value;
        }


        bool is_hex() const {
            return type == menu_type::hex_value;
        }


        bool is_signed() const {
            return type == menu_type::signed_value;
        }


        bool is_float() const {
            return type == menu_type::float_value;
        }


        bool is_positive_float() const {
            return type == menu_type::positive_float_value;
        }


        bool is_float_point() const {
            return type == menu_type::float_value || type == menu_type::positive_float_value;
        }


        bool is_option() const {
            return type == menu_type::option;
        }


        bool is_check() const {
            return type == menu_type::check;
        }


        bool is_comment() const {
            return type == menu_type::comment;
        }


        bool is_empty_comment() const {
            return is_comment() && len == 0;
        }


        bool is_help() const {
            return type == menu_type::comment && len > 0;
        }


        bool is_no_value() const {
            return type == menu_type::no_value;
        }


        // 是否为data 域里存储了指针的类型
        // 如果要保存菜单数据，应该忽略指针，因为程序修改后，保存的指针很可能会失效
        bool is_reference_type() const {
            return type == menu_type::option || type == menu_type::comment;
        }


        uint32_t unsigned_value() const {
            return data.u * multiplier();
        }


        int32_t signed_value() const {
            return data.s * multiplier();
        }


        float float_value() const {
            return data.f;
        }


        float positive_float_value() const {
            return data.f;
        }
    };


    class MenuPage {
       private:
        // beef::InterfaceBase *_parent;  // TODO

        const char* _clickable_cursor = nullptr;      // 用来表示光标的字符
        const char* _not_clickable_cursor = nullptr;  // 用来表示光标的字符
        const char* _special_cursor = nullptr;        // 用来表示特殊光标的字符
        const char* _special_mark = nullptr;          // 特殊菜单项未被选中时的前缀
        const char* _comment_cursor = nullptr;        // 用来表示注释行的字符
        const char* _none_cursor = nullptr;           // 没被选中的菜单项的前缀，可以添加空格把菜单项对齐
        const char* _delimiter = nullptr;             // 用来分隔菜单项label 和value 的字符

        MenuItem* _items;  // 菜单项数组

        uint32_t _not_clickable_mask = 0;  // 不可点击的菜单项掩码
        uint32_t _highlight_mask = 0;      // 反色显示的菜单项掩码
        uint32_t _special_mask = 0;        // 具有特殊cursor 的菜单项掩码

        PointType _display_offset_cursor_x = 0;
        PointType _display_offset_cursor_y = 0;
        PointType _row_hight = 0;  // 行高，单位像素
        PointType _width = 0;

        uint8_t _item_count;             // 菜单项数量
        uint8_t _selected_index = 0;     // 当前选中的菜单项索引
        uint8_t _display_row_count = 0;  // 屏幕上可见的菜单项行数

        bool _changed = false;  // 菜单项是否发生变化


        uint8_t visible_start_index() const {
            // 计算可见菜单项的起始索引
            // 算法原理参考：https://blog.csdn.net/Etberzin/article/details/149390359
            uint8_t _mid_row = _display_row_count / 2;  // 中间行索引，屏幕行数 / 2

            if (_item_count <= _display_row_count) {
                return 0;  // 所有菜单项都可见
            }
            else if (_selected_index < _mid_row) {
                return 0;  // 光标在顶部边界
            }
            else if (_selected_index >= _item_count - _mid_row) {
                return _item_count - _display_row_count;  // 光标在底部边界
            }
            else {
                return _selected_index - _mid_row;  // 光标在中间部分
            }
        }


        bool not_drawable() const {
            // 如果没有可见行或行高为0，则无法绘制菜单项
            return _display_row_count == 0 || _row_hight == 0 || _width == 0;
        }


        // 清除屏幕上显示菜单项的区域
        void clear_area() {
            if (not_drawable()) {
                return;
            }

            auto start_y = _display_offset_cursor_y;
            if (start_y > _row_hight) {
                start_y -= _row_hight - 1;
            }

            oled_clear_box(_display_offset_cursor_x, start_y, _width, _row_hight * _display_row_count);
        }


       public:
        static constexpr size_t CLICKABLE_FLAG_MAX_INDEX = (sizeof(_not_clickable_mask) * 8) - 1;
        static constexpr size_t HIGHLIGHT_FLAG_MAX_INDEX = (sizeof(_highlight_mask) * 8) - 1;
        static constexpr size_t SPECIAL_CURSOR_FLAG_MAX_INDEX = (sizeof(_special_mask) * 8) - 1;

        MenuPage(MenuItem* items, uint8_t item_count, uint8_t row_count) :
            _items(items),
            _item_count(item_count),
            _display_row_count(row_count) {
            // 限制菜单项数量最大为32
            // if (item_count > 32) {
            //     _item_count = 32;
            // }
        }


        void set_placing(PointType row_height, PointType width, PointType offset_x, PointType offset_y) {
            _row_hight = row_height;
            _width = width;
            _display_offset_cursor_x = offset_x;
            _display_offset_cursor_y = offset_y;
        }


        PointType row_height() const {
            return _row_hight;
        }


        PointType width() const {
            return _width;
        }


        PointType x() const {
            return _display_offset_cursor_x;
        }


        PointType y() const {
            return _display_offset_cursor_y;
        }


        void scroll_down(bool cycle = false) {
            if (_item_count == 0) return;

            if (_selected_index < _item_count - 1) {
                ++_selected_index;
                _changed = true;
            }
            else if (cycle) {
                _selected_index = 0;
                _changed = true;
            }
        }


        void scroll_up(bool cycle = false) {
            if (_item_count == 0) return;

            if (_selected_index > 0) {
                --_selected_index;
                _changed = true;
            }
            else if (cycle) {
                _selected_index = _item_count - 1;
                _changed = true;
            }
        }


        void scroll_to(uint8_t index) {
            if (index < _item_count) {
                _selected_index = index;
                _changed = true;
            }
        }


        void scroll_to_top() {
            scroll_to(0);
        }


        void scroll_to_bottom() {
            if (_item_count > 0) {
                scroll_to(_item_count - 1);
            }
        }


        MenuItem& selected_item() {
            return _items[_selected_index];
        }


        const MenuItem& selected_item() const {
            return _items[_selected_index];
        }


        uint8_t selected_index() const {
            return _selected_index;
        }


        bool is_top() const {
            return _selected_index == 0;
        }


        bool is_bottom() const {
            return _selected_index == (_item_count - 1);
        }


        MenuItem* item(uint8_t index) {
            if (index < _item_count) {
                return &_items[index];
            }
            return nullptr;
        }


        size_t item_count() const {
            return _item_count;
        }


        bool changed() const {
            return _changed;
        }


        void set_changed(bool changed) {
            _changed = changed;
        }


        bool clickable(uint8_t index) const {
            if (index >= _item_count || index > CLICKABLE_FLAG_MAX_INDEX)
                return false;
            return (_not_clickable_mask & (1 << index)) == 0;
        }


        /**
         * @brief 设置菜单项是否可点击
         *
         * 只有前32 个菜单项可以设置可点击状态。
         *
         * @param index 菜单项索引
         * @param clickable 是否可点击
         */
        void set_clickable(uint8_t index, bool clickable) {
            if (index < _item_count && index <= CLICKABLE_FLAG_MAX_INDEX) {
                if (clickable) {
                    _not_clickable_mask &= ~(1 << index);
                }
                else {
                    _not_clickable_mask |= (1 << index);
                }
            }
        }


        bool highlighted(uint8_t index) const {
            if (index >= _item_count || index > HIGHLIGHT_FLAG_MAX_INDEX)
                return false;
            return (_highlight_mask & (1 << index));
        }


        /**
         * @brief 设置菜单项高亮显示
         *
         * 只有前32 个菜单项可以设置高亮状态。
         *
         * @param index 菜单项索引
         * @param clickable 是否可点击
         */
        void set_highlighted(uint8_t index, bool flag) {
            if (index < _item_count && index <= HIGHLIGHT_FLAG_MAX_INDEX) {
                if (flag) {
                    _highlight_mask |= (1 << index);
                }
                else {
                    _highlight_mask &= ~(1 << index);
                }
            }
        }


        bool special(uint8_t index) const {
            if (index >= _item_count || index > SPECIAL_CURSOR_FLAG_MAX_INDEX)
                return false;
            return (_special_mask & (1 << index));
        }


        /**
         * @brief 设置菜单项为特殊显示
         *
         * 只有前32 个菜单项可以设置。
         *
         * @param index 菜单项索引
         * @param clickable 是否可点击
         */
        void set_special(uint8_t index, bool flag) {
            if (index < _item_count && index <= SPECIAL_CURSOR_FLAG_MAX_INDEX) {
                if (flag) {
                    _special_mask |= (1 << index);
                }
                else {
                    _special_mask &= ~(1 << index);
                }
            }
        }


        void set_clickable_cursor(const char* cursor) {
            _clickable_cursor = cursor;
        }


        void set_not_clickable_cursor(const char* cursor) {
            _not_clickable_cursor = cursor;
        }


        void set_special_cursor(const char* cursor) {
            _special_cursor = cursor;
        }


        void set_special_mark(const char* mark) {
            _special_mark = mark;
        }


        void set_comment_cursor(const char* cursor) {
            _comment_cursor = cursor;
        }


        void set_none_cursor(const char* cursor) {
            _none_cursor = cursor;
        }


        /**
         * @brief 根据当前选中的行，在屏幕选定区域内绘制可见的菜单项
         *
         * 为了简化绘制逻辑，不管菜单操作正在向上或向下滚动，只要选中同一个菜单项，绘制的内容就是相同的。
         *
         * 一般的滚动菜单绘制时需要考虑滚动方向，比如，菜单项总共有四行，而屏幕上总共能显示两行，那么向下滚动时，
         * 光标会固定在第二行，而向上滚动时，光标会固定在第一行。
         *
         * 向下滚动时：
         *
         *    菜单项1
         * >  菜单项2
         * >  菜单项3   👈  ↓
         *    菜单项4
         *
         *    菜单项1
         *    菜单项2
         * >  菜单项3
         * >  菜单项4   👈  ↓
         *
         * 向上滚动时：
         *
         *    菜单项1
         *    菜单项2
         * >  菜单项3
         * >  菜单项4   👈  ↑
         *
         *    菜单项1
         *    菜单项2
         * >  菜单项3   👈  ↑
         * >  菜单项4
         *
         * 左侧两个尖括号表示屏幕上可见的两行。选中菜单项3 时，如果是向下滚动，光标会在第二行，而向上滚动时，光标会在第一行。
         * 而且，向下时，选中菜单项3，可见的菜单项是菜单项2 和菜单项3，而向上滚动时，可见的菜单项是菜单项3 和菜单项4。
         * 如果屏幕上显示的行数更多，这套逻辑还会更麻烦。
         *
         * 所以这里采用简化的方案，如果屏幕上能显示三行，则光标会暂时固定在中间第二行，这样如果选中了菜单项2，那么屏幕上要显示的
         * 一定是1 到3 三个菜单项，如果选中了菜单项3，那么屏幕上要显示的就是2 到4 三个菜单项。
         *
         * 当菜单滚动到开头或结尾时，才移动光标。效果如下：
         *
         * 向下滚动时：
         *
         * >  菜单项1    👈  ↓
         * >  菜单项2
         * >  菜单项3
         *    菜单项4
         *
         * >  菜单项1
         * >  菜单项2    👈  ↓
         * >  菜单项3
         *    菜单项4
         *
         *    菜单项1
         * >  菜单项2
         * >  菜单项3    👈  ↓
         * >  菜单项4
         *
         *    菜单项1
         * >  菜单项2
         * >  菜单项3
         * >  菜单项4    👈  ↓
         *
         * 光标位置算法：
         *
         * 设屏幕行数为3，3 / 2 = 1，则所有菜单项中，正数第一个项的光标在第一行，倒数第一个的光标在倒数第一行，
         * 选中其他菜单项时，光标都在中间的第二行；
         * 如果屏幕行数为5，5 / 2 = 2，则正数第一个项的光标在第一行，第二个的光标在第二行，倒数第一个项光标在倒数第一行，
         * 倒数第二个项的光标在倒数第二行，选中其他菜单项时，光标都在中间的第三行。
         *
         * 依次类推。如果屏幕行数为偶数，比如行数为2，则规则和行数为3 时相同。
         *
         * 如果菜单项数小于等于屏幕行数，则光标行数和菜单项数相同，不做以上计算。如果屏幕只有一行，则光标始终在第一行，
         * 也不用计算。
         *
         * 可见菜单项算法：
         *
         * 先计算光标位置，然后根据光标位置和屏幕行数，计算可见菜单项的起始索引和结束索引。
         * 比如，如果光标在第一行，屏幕行数为3，则可见菜单项的起始索引为0，结束索引为2；
         * 如果光标在第二行，屏幕行数为3，则可见菜单项的起始索引是当前选中索引减1；
         *
         *
         * @param is_initial
         * @return true
         * @return false
         */
        bool draw(bool is_initial) {
            if (not_drawable()) {
                // 如果没有可见行或行高为0，则无法绘制菜单项
                return false;
            }

            if (!is_initial) {
                if (!_changed) {
                    // 没有变化，不需要重绘
                    return false;
                }
            }

            _changed = false;
            clear_area();
            u8g2.setFont(MENU_FONT); // TODO: 字体管理器, 为所有对象提供最多四个可选的字体，并且可以全局的动态调整每个字体实际映射到哪个字库，相当于可以切换主题
            // uint8_t cursor_row = selected_row();
            uint8_t visible_start = visible_start_index();
            uint8_t count = min(_display_row_count, _item_count);

            for (uint8_t i = 0; i < count; ++i) {
                uint8_t index = visible_start + i;
                // if (index >= _item_count) break;  // 防止越界

                MenuItem& item = _items[index];
                u8g2.setCursor(_display_offset_cursor_x, _display_offset_cursor_y + i * _row_hight);

                // 高亮反色效果
                if (highlighted(index)) {
                    u8g2.setDrawColor(0);  // 反色
                }
                else {
                    u8g2.setDrawColor(1);
                }

                if (index == _selected_index) {
                    // 绘制选中项的光标
                    if (special(index)) {
                        // 绘制特殊光标
                        u8g2.print(_special_cursor ? _special_cursor : " ");
                    }
                    else if (item.is_comment()) {
                        u8g2.print(_comment_cursor ? _comment_cursor : "? ");  // 注释行
                    }
                    else {
                        if (clickable(index)) {
                            u8g2.print(_clickable_cursor ? _clickable_cursor : "> ");  // 可点击项，前面加上">"符号
                        }
                        else {
                            u8g2.print(_not_clickable_cursor ? _not_clickable_cursor : "# ");  // 不可点击项，前面加上"#"符号
                        }
                    }
                }
                else if (_none_cursor) {
                    // 绘制未选中项的前
                    if (special(index) && _special_mark) {
                        u8g2.print(_special_mark);
                    }
                    else {
                        u8g2.print(_none_cursor);  // 没被选中的菜单项，前面可以加上空格对齐
                    }
                }

                u8g2.print(item.label);
                if (!(item.is_comment() || item.is_no_value())) {
                    // 如果菜单项有值，则打印分隔符
                    u8g2.print(_delimiter ? _delimiter : " ");
                }

                switch (item.type) {
                    case menu_type::no_value:
                    case menu_type::comment:  // comment 类型可能含有附加帮助信息，但不直接显示
                        break;

                    case menu_type::unsigned_value:
                        u8g2.print(item.unsigned_value());
                        break;

                    case menu_type::signed_value:
                        u8g2.print(item.signed_value());
                        break;

                    case menu_type::hex_value:
                        u8g2.print("H");
                        u8g2.print(item.unsigned_value(), HEX);
                        break;

                    case menu_type::float_value:
                    case menu_type::positive_float_value:
                        u8g2.print(item.data.f, item.float_precision());
                        break;

                    case menu_type::option: {
                        if (item.index >= item.len) {
                            item.index = 0;  // 确保索引不越界
                        }
                        const char* option = item.data.list[item.index];
                        if (option != nullptr) {
                            u8g2.print(option);
                        }
                    } break;

                    case menu_type::check:
                        if (item.checked()) {
                            u8g2.print("ON");
                        }
                        else {
                            u8g2.print("OFF");
                        }
                        break;
                }
            }

            return true;  // 返回true表示菜单项已成功绘制
        }
    };


    inline int export_menu_data(MenuItem* items, int item_count, uint8_t* buffer, size_t buffer_size) {
        if (items == nullptr || buffer == nullptr || buffer_size == 0) {
            return -1;  // 参数无效
        }

        int pos = 0;
        for (int i = 0; i < item_count; ++i) {
            const auto& item = items[i];
            if(item.is_no_value() || item.is_comment()) {
                // no_value 和 comment 类型不保存数据
                continue;
            }
            size_t item_size = 2 + (item.is_reference_type() ? 0 : sizeof(MenuItemData));

            if (buffer_size - pos < item_size) {
                return -1;
            }

            // 写入index
            buffer[pos++] = item.index;
            // 写入id
            buffer[pos++] = item.id;

            if (!item.is_reference_type()) {
                // 写入data
                memcpy(&buffer[pos], &item.data, sizeof(MenuItemData));
                pos += sizeof(MenuItemData);
            }
        }

        return pos;
    }


    inline int import_menu_data(MenuItem* items, int item_count, const uint8_t* buffer, size_t buffer_size) {
        if (items == nullptr || buffer == nullptr || buffer_size == 0) {
            return -1;  // 参数无效
        }

        int pos = 0;
        for (int i = 0; i < item_count; ++i) {
            auto& item = items[i];
            if(item.is_no_value() || item.is_comment()) {
                // no_value 和 comment 类型不保存数据
                continue;
            }
            size_t item_size = 2 + (item.is_reference_type() ? 0 : sizeof(MenuItemData));

            if (buffer_size - pos < item_size) {
                return -1;
            }

            // 读取index
            item.index = buffer[pos++];
            // 读取id
            item.id = buffer[pos++];

            // 读取data
            // 如果类型是comment、option，data 里存储的是指针，
            // 就跳过这部分数据。
            // 需要注意，当菜单列表修改后，菜单类型可能会变化，就会导致数据读取错误，
            // 所以当菜单列表修改后，就要更新STORAGE_VERSION 的值，舍弃之前存储的数据。
            if (!item.is_reference_type()) {
                // 读取data
                memcpy(&item.data, &buffer[pos], sizeof(MenuItemData));

                pos += sizeof(MenuItemData);
            }
        }
        return pos;
    }


    inline int export_menu_data(MenuItem* items, int item_count, Stream& stream) {
        if (items == nullptr) {
            return -1;  // 参数无效
        }

        int total_bytes = 0;
        for (int i = 0; i < item_count; ++i) {
            const auto& item = items[i];
            if(item.is_no_value() || item.is_comment()) {
                // no_value 和 comment 类型不保存数据
                continue;
            }
            size_t item_size = 2 + (item.is_reference_type() ? 0 : sizeof(MenuItemData));

            uint8_t buffer[sizeof(MenuItemData) + 2];
            // 写入index
            buffer[0] = item.index;
            // 写入id
            buffer[1] = item.id;

            if (!item.is_reference_type()) {
                // 写入data
                memcpy(&buffer[2], &item.data, sizeof(MenuItemData));
            }

            size_t written = stream.write(buffer, item_size);
            if (written != item_size) {
                return -1;  // 写入失败
            }
            total_bytes += written;
        }
        return total_bytes;
    }


    inline int import_menu_data(MenuItem* items, int item_count, Stream& stream) {
        if (items == nullptr) {
            return -1;  // 参数无效
        }

        int total_bytes = 0;
        for (int i = 0; i < item_count; ++i) {
            auto& item = items[i];
            if(item.is_no_value() || item.is_comment()) {
                // no_value 和 comment 类型不保存数据
                continue;
            }
            size_t item_size = 2 + (item.is_reference_type() ? 0 : sizeof(MenuItemData));

            uint8_t buffer[sizeof(MenuItemData) + 2];
            size_t read_bytes = stream.readBytes(reinterpret_cast<char*>(buffer), item_size);
            if (read_bytes != item_size) {
                return -1;  // 读取失败
            }

            // 读取index
            item.index = buffer[0];
            // 读取id
            item.id = buffer[1];

            if (!item.is_reference_type()) {
                // 读取data
                memcpy(&item.data, &buffer[2], sizeof(MenuItemData));
            }

            total_bytes += read_bytes;
        }
        return total_bytes;
    }

}  // namespace beef